---
title: Extract page ranges from a PDF
summary: Build a new PDF from selected page ranges of a source PDF, honoring ascending/descending and open-ended ranges.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-09-17
library: PdfAPI.SyncFusionCore
reference_type: package
operation_id: OP-SFC-011
trigger: Caller request (SyncfusionPdfService.Extract); also called internally by the merge operation
---

# Extract page ranges from a PDF

Builds a new PDF composed of one or more page ranges pulled from a source PDF. Supports ascending and descending ranges, open-ended stop pages, and clamps or skips ranges that fall outside the document. Unlike single-document conversion, failures here are not captured — they propagate.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-SFC-011 |
| **Trigger** | Caller request — `SyncfusionPdfService.ExtractPages(request)` (`PdfAPI\Services\Syncfusion\SyncfusionPdfService.cs:187`) — and internally by [Merge document ranges into one PDF](merge-document-ranges-into-one-pdf.md) step 3 |
| **Inputs** | `ExtractPagesRequest` (`DocumentRange` with a `Document` and a list of `PageRange`, `Options`). The overload `Extract(DocumentRange, PdfFormat)` wraps its arguments in a new `ExtractPagesRequest` with `Options = new PdfOptions(outputFormat)` and calls this operation. |
| **Outputs** | `byte[]` of the assembled PDF |
| **Primary components** | `PdfExtractor.Extract` |
| **Entry point** | `PdfApi.SyncFusionCore\Extract\PdfExtractor.cs` |

## Steps

1. Short-circuit: when the range list holds exactly one `PageRange` and that range `IsOriginal`
   (`1`–`*`), return `documentRange.Document.File` unchanged — no Syncfusion work and no PDF/A upgrade on this path ([BR-SFC-024](../business-rules.md#br-sfc-024-full-document-range-returned-unchanged)).
2. Choose conformance: `Pdf_A1B` when `Options.IsPdfa`, otherwise `None` ([BR-SFC-011](../business-rules.md#br-sfc-011-pdf%2Fa-conformance-level-a1b)).
3. Load the source bytes as a `PdfLoadedDocument` and record `totalPages`.
4. Create the output `PdfDocument` with the chosen conformance.
5. For each `PageRange`: skip the range entirely when both `StartPage` and `StopPage` exceed
   `totalPages`; otherwise clamp each bound down to `totalPages` ([BR-SFC-025](../business-rules.md#br-sfc-025-out-of-range-pages-clamped-or-skipped)).
6. When `StopPage >= StartPage` (or `StopPage == -1`, which is first resolved to `totalPages`),
   import pages ascending; otherwise import descending, i.e. a reversed range produces reversed page order. Page numbers are 1-based in the range and converted with `i - 1` for `ImportPage` ([BR-SFC-026](../business-rules.md#br-sfc-026-open-ended-stop-page-means-last-page), [BR-SFC-027](../business-rules.md#br-sfc-027-descending-range-reverses-page-order)).
7. Save the assembled document to a `MemoryStream` and capture the bytes.
8. When `Options.IsPdfa`, reload the saved bytes as a `PdfLoadedDocument`, set
   `Conformance = Pdf_A1B`, save again and replace the output — a second PDF/A pass over the already-conformant output ([BR-SFC-020](../business-rules.md#br-sfc-020-pdf%2Fa-applied-via-reload-and-resave)).
9. Return the bytes.
   - On failure: any Syncfusion exception propagates directly to the caller. No exception handling
     wraps this operation ([BR-SFC-028](../business-rules.md#br-sfc-028-extraction-and-merge-failures-propagate)).

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start(["Extract called with<br>ExtractPagesRequest"]) --> SingleFull{"Single original<br>1-to-* range?"}
	SingleFull -->|Yes| ReturnAsIs(["Return source bytes<br>unchanged"])
	SingleFull -->|No| Conf["Choose conformance,<br>load source as<br>PdfLoadedDocument"]
	Conf --> CreateOut[Create output PdfDocument]
	CreateOut --> ForEach{"More PageRanges<br>to process?"}
	ForEach -->|Yes| RangeCheck{"Range entirely<br>beyond totalPages?"}
	RangeCheck -->|Yes| Skip[Skip this range]
	RangeCheck -->|No| Clamp["Clamp bounds to<br>totalPages"]
	Clamp --> DirCheck{"StopPage >= StartPage?"}
	DirCheck -->|Yes| Ascend[Import pages ascending]
	DirCheck -->|No| Descend[Import pages descending]
	Ascend --> ForEach
	Descend --> ForEach
	Skip --> ForEach
	ForEach -->|No| Save[Save to MemoryStream]
	Save --> PdfaCheck{"Options.IsPdfa?"}
	PdfaCheck -->|Yes| Reload["Reload bytes, set<br>Conformance = Pdf_A1B,<br>save again"]
	PdfaCheck -->|No| Return([Return PDF bytes])
	Reload --> Return
```

## Failure and edge-case behavior

- Any Syncfusion failure during load, import, or save propagates directly to the caller — this
  operation has no `catch` block, unlike single-document conversion.
- A range with both bounds beyond `totalPages` contributes nothing to the output rather than
  raising an error.
- The full-document short-circuit (step 1) bypasses the PDF/A upgrade entirely, even when the
  caller requested PDF/A.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

## Sources
- `PdfApi.SyncFusionCore\Extract\PdfExtractor.cs`
- `PdfAPI\Services\Syncfusion\SyncfusionPdfService.cs`
